package com.mazaiting.manager.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mazaiting.common.core.domain.result.Option;
import com.mazaiting.common.core.domain.result.ResultCode;
import com.mazaiting.common.core.ex.exceptions.BusinessException;
import com.mazaiting.common.core.ex.exceptions.EmptyObjectException;
import com.mazaiting.manager.constant.SystemConstant;
import com.mazaiting.manager.convert.IDeptConverter;
import com.mazaiting.manager.domain.entity.SysDept;
import com.mazaiting.manager.domain.form.DeptForm;
import com.mazaiting.manager.domain.query.DeptQuery;
import com.mazaiting.manager.domain.vo.dept.DeptDetailVO;
import com.mazaiting.manager.domain.vo.dept.DeptVO;
import com.mazaiting.manager.mapper.ISysDeptMapper;
import com.mazaiting.manager.service.ISysDeptService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 部门表 服务实现类
 * </p>
 *
 * @author mazaiting
 * @since 2022-09-20
 */
@Service
@RequiredArgsConstructor
public class SysDeptServiceImpl extends ServiceImpl<ISysDeptMapper, SysDept> implements ISysDeptService {

    private final IDeptConverter deptConverter;

    @Override
    public List<DeptVO> list(DeptQuery queryParams) {
        // 查询参数
        String keywords = queryParams.getKeywords();
        Boolean enabled = queryParams.getEnabled();

        // 查询数据
        List<SysDept> deptList = this.list(
                new LambdaQueryWrapper<SysDept>()
                        .like(StrUtil.isNotBlank(keywords), SysDept::getName, keywords)
                        .eq(Validator.isNotNull(enabled), SysDept::getEnabled, enabled)
                        .orderByAsc(SysDept::getSort)
        );
        return recurDepartments(deptList);
    }

    @Override
    public List<Option<Long>> listDeptOptions() {
        List<SysDept> deptList = lambdaQuery().eq(SysDept::getEnabled, true)
                .select(SysDept::getId, SysDept::getParentId, SysDept::getName)
                .orderByAsc(SysDept::getSort).list();
        return recurDeptTreeOptions(SystemConstant.ROOT_DEPT_ID, deptList);
    }

    @Override
    public boolean save(DeptForm formData) throws BusinessException {
        // 根据用户名与父 ID 查询是否已经存在部门
        Optional<SysDept> sysDeptOpt = lambdaQuery().eq(SysDept::getName, formData.getName())
                .eq(SysDept::getParentId, formData.getParentId()).oneOpt();
        if (sysDeptOpt.isPresent()) {
            throw new BusinessException(ResultCode.DEPT_EXIST);
        }
        return save(deptConverter.form2Entity(formData));
    }

    @Override
    public DeptDetailVO getDeptDetail(Long deptId) throws EmptyObjectException {
        SysDept sysDept = lambdaQuery().eq(SysDept::getId, deptId)
                .select(SysDept::getId, SysDept::getName, SysDept::getParentId, SysDept::getEnabled, SysDept::getSort)
                .oneOpt()
                .orElseThrow(() -> new EmptyObjectException(ResultCode.DEPT_NOT_EXIST));

        return deptConverter.entity2DetailVO(sysDept);
    }

    @Override
    public boolean update(DeptForm formData) throws EmptyObjectException {
        SysDept sysDept = baseMapper.selectById(formData.getId());
        if (Objects.isNull(sysDept)) {
            throw new EmptyObjectException(ResultCode.DEPT_NOT_EXIST);
        }
        // form -> entity
        deptConverter.updateForm2Entity(formData, sysDept);
        // 保存部门并返回部门ID
        return updateById(sysDept);
    }

    @Override
    public boolean deleteByIds(String ids) {
        // 此处进行分割后遍历是为了确保 ID 的有效性
        List<Long> idList = Arrays.stream(ids.split(",")).mapToLong(Long::parseLong).boxed().toList();
        if (CollectionUtil.isEmpty(idList)) return true;
        // 同步列表
        List<Long> list = Collections.synchronizedList(new ArrayList<>());
        // 批量查询所有部门及子部门
        idList.forEach(deptId -> list.addAll(baseMapper.findByParentId(deptId)));
        // 删除部门及子部门
        return removeByIds(list);
    }

    /**
     * 递归生成部门表格层级列表
     *
     * @param parentId 父菜单 ID
     * @param deptList 部门列表
     * @return 表格层级列表
     */
    public static List<Option<Long>> recurDeptTreeOptions(long parentId, List<SysDept> deptList) {
        // 空部门列表
        if (CollectionUtil.isEmpty(deptList)) {
            return Collections.emptyList();
        }

        return deptList.stream()
                // 父菜单ID相等
                .filter(dept -> dept.getParentId().equals(parentId))
                .map(dept -> {
                    Option<Long> option = new Option<>(dept.getId(), dept.getName());
                    // 获取子部门
                    List<Option<Long>> children = recurDeptTreeOptions(dept.getId(), deptList);
                    if (CollectionUtil.isNotEmpty(children)) {
                        option.setChildren(children);
                    }
                    return option;
                })
                .collect(Collectors.toList());
    }


    /**
     * 递归生成部门表格层级列表
     *
     * @param deptList 部门列表
     * @return 部门列表
     */
    private List<DeptVO> recurDepartments(List<SysDept> deptList) {
        List<DeptVO> deptTableList = new ArrayList<>();
        // 保存所有节点的 id
        Set<Long> nodeIdSet = deptList.stream()
                .map(SysDept::getId)
                .collect(Collectors.toSet());
        for (SysDept sysDept : deptList) {
            // 不在节点 id 集合中存在的 id 即为顶级节点 id, 递归生成列表
            Long parentId = sysDept.getParentId();
            if (!nodeIdSet.contains(parentId)) {
                deptTableList.addAll(recurTableDepts(parentId, deptList));
                nodeIdSet.add(parentId);
            }
        }
        // 如果结果列表为空说明所有的节点都是独立分散的, 直接转换后返回
        if (deptTableList.isEmpty()) {
            return deptList.stream()
                    .map(deptConverter::entity2VO)
                    .collect(Collectors.toList());
        }
        return deptTableList;
    }


    /**
     * 递归生成部门表格层级列表
     *
     * @param parentId 父ID
     * @param deptList 部门列表
     * @return 部门层级列表
     */
    public List<DeptVO> recurTableDepts(Long parentId, List<SysDept> deptList) {
        List<DeptVO> deptTableList = new ArrayList<>();
        Optional.ofNullable(deptList).orElse(new ArrayList<>())
                .stream()
                .filter(dept -> dept.getParentId().equals(parentId))
                .forEach(dept -> {
                    DeptVO deptVO = deptConverter.entity2VO(dept);
                    List<DeptVO> children = recurTableDepts(dept.getId(), deptList);
                    deptVO.setChildren(children);
                    deptTableList.add(deptVO);
                });
        return deptTableList;
    }
}
